package service

import (
	"encoding/json"
	"fmt"
	"gadmin/conf"
	"gadmin/model"
	"gadmin/service/plugins"
	"os"
	"path"

	"github.com/goccy/go-yaml"
)

func ParseDefinition(rawData string) (definition *model.WorkflowDefinition, err error) {
	definition = new(model.WorkflowDefinition)
	err = yaml.Unmarshal([]byte(rawData), definition)
	if err != nil {
		return nil, err
	}
	return definition, nil
}

func CreateWorkflow(rawData string) error {
	var workflow model.Workflow
	definition, err := ParseDefinition(rawData)
	if err != nil {
		return err
	}
	// workflow.ID = uuid.New().String()
	workflow.Name = definition.Name
	workflow.Desc = definition.Desc
	workflow.Definition = rawData
	err = model.DB.Save(&workflow).Error
	if err != nil {
		return err
	}
	return nil
}

func UpdateWorkflow(uuid string, definitionStr string) (err error) {
	var workflow model.Workflow

	definition, err := ParseDefinition(definitionStr)
	if err != nil {
		return err
	}

	result := model.DB.First(&workflow, "id = ?", uuid)
	if result.Error != nil {
		return result.Error
	}
	workflow.Definition = definitionStr
	workflow.Name = definition.Name
	workflow.Desc = definition.Desc
	return model.DB.Save(&workflow).Error
}

func GetWorkflow() (workflows []model.Workflow, err error) {
	result := model.DB.Order("created_at desc").Find(&workflows)
	if result.Error != nil {
		return nil, result.Error
	}
	return workflows, nil
}

func FindWorkflow(uuid string) (workflow *model.Workflow, err error) {
	workflow = new(model.Workflow)
	result := model.DB.First(workflow, "id = ?", uuid)
	if result.Error != nil {
		return nil, result.Error
	}
	return workflow, nil
}

func RunWorkerWithName(name string, inputs map[string]string, sync bool) (workflowHistory *model.WorkflowHistory, data interface{}, err error) {
	var workflow model.Workflow
	result := model.DB.First(&workflow, "name = ?", name)
	if result.Error != nil {
		return nil, nil, result.Error
	}
	return RunWorker(workflow.ID, inputs, sync)
}

func RunWorker(_uuid uint, inputs map[string]string, sync bool) (workflowHistory *model.WorkflowHistory, data interface{}, err error) {
	var workflow model.Workflow
	result := model.DB.Find(&workflow, "id = ?", _uuid)

	if result.Error != nil {
		return nil, nil, result.Error
	}

	if inputs == nil {
		inputs = make(map[string]string)
	}

	definition, err := ParseDefinition(workflow.Definition)
	if err != nil {
		return nil, nil, err
	}

	for _, value := range definition.Inputs {
		if _, exists := inputs[value.Name]; !exists {
			inputs[value.Name] = value.Value
		}
	}

	// 创建History
	workflowHistory = new(model.WorkflowHistory)
	// workflowHistory.ID = uuid.New().String()
	workflowHistory.Name = workflow.Name
	workflowHistory.Desc = workflow.Desc
	workflowHistory.WorkflowID = workflow.ID
	workflowHistory.Status = "not_start"
	workflowHistory.Definition = workflow.Definition
	result = model.DB.Create(&workflowHistory)
	if result.Error != nil {
		return nil, nil, result.Error
	}

	for index, _step := range definition.Steps {
		var step model.StepHistory

		if index == 0 {
			content, err := json.Marshal(inputs)
			if err != nil {
				return nil, nil, err
			}
			step.Input = string(content)
		}
		// step.ID = uuid.New().String()
		step.WorkflowHistoryID = workflowHistory.ID
		step.Index = index
		step.Name = _step.Name
		step.Alias = _step.Alias
		step.Type = _step.Type
		step.Status = "not_start"
		step.Code = _step.Code
		result = model.DB.Create(&step)
		if result.Error != nil {
			return nil, nil, result.Error
		}
	}

	if sync {
		output := RunDaemon(workflowHistory.ID)
		return nil, output, nil
	} else {
		go RunDaemon(workflowHistory.ID)
	}
	return workflowHistory, nil, nil
}

// 后台执行任务
func RunDaemon(_uuid uint) (output string) {
	var workflowHistory model.WorkflowHistory
	result := model.DB.Find(&workflowHistory, "id = ?", _uuid)
	if result.Error != nil {
		fmt.Errorf("找不到 {} 这个执行任务.", _uuid)
		return
	}

	defer func() {
		if r := recover(); r != nil {
			fmt.Errorf("执行任务失败,报错: %v\n", r)
			workflowHistory.Status = "error"
			err := model.DB.Save(workflowHistory).Error
			if err != nil {
				fmt.Printf("任务执行失败,同时更新任务状态为Error出错")
				return
			}
		}
	}()

	// 创建工作目录
	err := os.MkdirAll(path.Join(conf.Conf.Workdir, fmt.Sprintf("%d", _uuid)), os.ModePerm)
	if err != nil {
		panic(err)
	}

	// 切换工作目录
	err = os.Chdir(path.Join(conf.Conf.Workdir, fmt.Sprintf("%d", _uuid)))
	if err != nil {
		panic(err)
	}

	// 设置为执行中
	workflowHistory.Status = "running"
	result = model.DB.Save(workflowHistory)
	if result.Error != nil {
		panic(result.Error)
	}

	// 获取所有步骤
	workflowHistory.Steps = make([]model.StepHistory, 0)
	result = model.DB.Order("`index`").Find(&workflowHistory.Steps, "workflow_history_id = ?", _uuid)
	if result.Error != nil {
		panic(result.Error)
	}

	// 执行每一步
	for ind, _ := range workflowHistory.Steps {
		plugins.RunPlugin(ind, workflowHistory.Steps)
	}

	// 设置为结束
	workflowHistory.Status = "finish"
	result = model.DB.Save(workflowHistory)
	if result.Error != nil {
		panic(result.Error)
	}

	return workflowHistory.Steps[len(workflowHistory.Steps)-1].Output
}

func GetWorkflowHistoryByWorkflowId(_uuid string) (history []model.WorkflowHistory, err error) {
	result := model.DB.Order("created_at desc").Where("workflow_id = ?", _uuid).Find(&history)
	if result.Error != nil {
		return nil, result.Error
	}
	return history, nil
}

func GetWorkflowHistoryByHistoryId(_uuid string) (history *model.WorkflowHistory, err error) {
	history = new(model.WorkflowHistory)
	result := model.DB.First(history, "id = ?", _uuid)
	if result.Error != nil {
		return nil, result.Error
	}

	history.Steps = make([]model.StepHistory, 0)
	result = model.DB.Order("`index`").Find(&history.Steps, "workflow_history_id = ?", _uuid)
	if result.Error != nil {
		return nil, result.Error
	}

	return history, nil
}
